package com.xxkk.spring_boot_web.utils;

import org.springframework.stereotype.Component;

import java.io.Closeable;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class ServerPool implements Closeable {
    private ScheduledThreadPoolExecutor executor;
    private static ServerPool instance;

    public static class BusinessPoolThreadFactory implements ThreadFactory {
        final ThreadGroup group = Thread.currentThread().getThreadGroup();
        final AtomicInteger threadNumber = new AtomicInteger(1);
        final String namePrefix = "server-pool";

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

    public ServerPool() {
        this.executor = new ScheduledThreadPoolExecutor(16, new BusinessPoolThreadFactory());
    }

    /**
     * 通过单例模式获取
     *
     * @return ServerPool
     */
    public static ServerPool ins() {
        if (instance == null) {
            synchronized (ServerPool.class) {
                if (instance == null)
                    instance = new ServerPool();
            }
        }
        return instance;
    }

    /**
     * @param runnable
     */
    public void execute(Runnable runnable) {
        executor.execute(() -> {
            try {
                runnable.run();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 提交一个Callable任务
     *
     * @param task
     * @param <T>
     * @return Future
     */
    public <T> Future<T> submit(Callable<T> task) {
        return executor.submit(task);
    }

    public void close() {
        if (executor != null)
            executor.shutdown();
    }

    /**
     * 不要使用，未测试过
     * 重复尝试执行任务以达到预期
     *
     * @param timeDelay    延时执行
     * @param timeOut      超时时间
     * @param times        执行失败重复尝试次数
     * @param unit         延时执行时间单位
     * @param callable     执行任务
     * @param flag         预期
     * @param default_task 任务失败执行操作
     * @param <V>
     */
    public <V extends Integer> void recursion(long timeDelay, long timeOut, int times, TimeUnit unit, Callable<V> callable, V flag, Runnable default_task) {
        if (timeDelay >= timeOut)
            throw new IllegalArgumentException("timeDelay >= timeOut");
        if (times <= 0) {//任务执行失败
            executor.submit(default_task);
        }
        Future<V> future = executor.schedule(callable, timeDelay, unit);
        try {
            V val_ = future.get(timeOut, unit);
            if (val_ == null || !val_.equals(flag)) {
                recursion(timeDelay, timeOut, --times, unit, callable, flag, default_task);
            }
        } catch (InterruptedException | ExecutionException e) {//任务中断
            executor.submit(default_task);
            e.printStackTrace();
        } catch (TimeoutException e) {
            recursion(timeDelay, timeOut, --times, unit, callable, flag, default_task);
        }
    }

    public ScheduledThreadPoolExecutor getExecutor() {
        return executor;
    }

    /**
     * 延迟执行一次任务
     *
     * @param command
     * @param delay
     * @param unit
     */
    public void scheduleOnce(Runnable command, long delay, TimeUnit unit) {
        this.executor.schedule(command, delay, unit);
    }

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
        return this.executor.scheduleWithFixedDelay(command, initialDelay, delay, unit);
    }
//
//    public int getActiveThreadNum() {
//        return executor.getActiveCount();
//    }
//
//    public int getMaxThreadNum() {
//        return executor.getMaximumPoolSize();
//    }
//
//    public ScheduledThreadPoolExecutor getExecutor() {
//        return executor;
//    }

//	public Map<String, ScheduledFuture<?>> getScheduleFutureMap() {
//		return scheduledFutureMap;
//	}
//
//	public void addScheduleFuture(String name, ScheduledFuture<?> scheduleFuture) {
//		this.scheduledFutureMap.put(name, scheduleFuture);
//	}
//
//	public void removeScheduleFuture(String name) {
//		this.scheduledFutureMap.remove(name);
//	}

}
